package 富婆梦.第一阶段.Java基础视频学习.线程的练习.作业3;

import java.util.ArrayList;

/**
 * @ProjectName: java-learning
 * @Package: 富婆梦.第一阶段.线程的练习.作业三
 * @ClassName: Container
 * @Author: hemengjin
 * @Description: 练习题2：自定义容器
 * 自定义容器，提供新增元素（add）和查看元素（get）方法。add方法向容器末尾位置新增元素，get方法通过参数传递的下标返回对应位置的元素。注意：get方法只读，不会删除对应位置的元素数据。
 * 要求为：
 * 1、容器提供读写锁能力
 * 2、写写互斥、读写互斥，多线程并发访问当前容器，只能有一个线程做写操作，可以有多个线程同时执行读操作。
 * 3、读写锁解释：当有任意线程执行写操作，则其他所有线程阻塞等待；当有任意线程执行读操作，则其他所有写线程阻塞，读线程可执行。
 *
 * 提示：
 * 1、定义一个容器类，其中定义一个任意集合类型的属性，提供add方法和get方法。
 * 2、在类中定义一个属性作为写入锁对象，定义一个boolean类型属性用于记录当前容器状态是否是写入状态。
 * 3、定义add方法，方法中定义同步代码块，对写入锁对象加锁。判断容器当前是否是写入状态，
 * 4、如果是在调用锁对象的wait方法，进入等待状态；在同步代码块中将boolean类型属性赋值为true，标记为当前是写入状态，其他线程不可操作容器；
 * 5、在同步代码块执行结束前，将boolean类型属性赋值为false，标记写入结束，其他线程可以操作容器，并且调用锁对象的notifyAll方法唤醒其他所有线程。
 * 6、定义get方法，方法中先使用while循环来判断当前容器是否是写入状态，如果是写入状态，当前线程休眠1毫秒（也称为自旋）；如果不是写入状态，则读取容器中对应下标的元素。
 * @Date:2021/11/1 14:23
 * @Version: 1.0
 */
public class Container {
    ArrayList<Integer> list = new ArrayList();
    boolean isAdd = false;
    boolean isGet = false;
    Object write = new Object();

    //添加元素方法
    public void add(int num) {
        while (isGet) {
            System.out.println("有线程正在查看元素，我先等2秒钟吧！");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        while (isAdd) {
            System.out.println("有线程正在添加元素，我先等2秒钟吧！");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            synchronized (write) {
                isAdd = true;
                list.add(num);
            }
            System.out.println(Thread.currentThread().getName() + "添加元素成功！数字为" + num);
        } finally {
            isAdd = false;
        }
    }

    //获取元素方法
    public int get(int index) {
        if (index > list.size() - 1 || index < 0) {
            System.out.println("请输入正确的index！");
        }
        while (isAdd) {
            System.out.println("有线程正在添加元素，我先等2秒钟吧！");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        int x;
        try {
            isGet = true;
            x = list.get(index);
        } finally {
            isGet = false;
        }
        return x;
    }

    public static void main(String[] args) {
        Container container = new Container();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    container.add(i);
                    try {
                        Thread.sleep(10);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    System.out.println(Thread.currentThread().getName() + "查看元素成功:" + container.get(i));
                    try {
                        Thread.sleep(10);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        });
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}
